const fs = require('fs');
const {promises} = fs;
const {stat, access} = promises;

const {extname, resolve, normalize, parse} = require('path');
//返回文件相关逻辑

/**
 * 根据 path 返回对应内容
 * @param {*} ctx 
 * @param {*} path 
 * @param {*} opts root 为绝对路径
 */
async function send(ctx, path, opts = {}) {
    const root = opts.root?normalize(resolve(opts.root)):'';
    const index = opts.index;
    const maxage = opts.maxAge||0;
    const immutable = opts.immutable;
    const format = !opts.format;  //默认为 false
    const tailSlash = path[path.length-1]==='/'; //是否以 / 结尾
    console.log('tailSlash:');
    console.log(path[path.length-1]);
    console.log(tailSlash);
    //去掉path 开头的 /，一般这种路径 parse 之后，root 就是 /
    path = path.substr(parse(path).root.length);
    //为什么要整个处理，难道不是应该仅处理 query
    path = decode(path);

    if(path==-1){
        console.log('path decode 失败');
        return ctx.throw(400, 'failed to decode');
    }
    //index 有配置，且以 / 结尾
    if(index && tailSlash){
        path+=index;
        console.log('以为 / 结尾，最终的 path 为 :'+path);
    } 

    //获取绝对路径
    path = resolve(root, path);
    //需要在此判断文件存在与否
    try{
        console.log('检测文件存在与否');
        await access(path);
    }catch(err){
        console.log('文件不存在');
        return true;
    }
    let stats;
    console.log('资源的绝对路径：'+path);
    try{
        //这里是不是应该先判断文件存在与否
        console.log('开始读取文件内容：');
        stats = await stat(path);
        console.log('读取到的文件内容：');
        console.log(stats);
    }catch(err){
        const notfound = ['ENOENT','ENAMETOOLONG','ENOTDIR'];
        console.log('err:');
        console.log(err);
        if(notfound.includes(err.code)){
            //createError 来自 http-error 库，可以快速创建 HTTP 错误对象
            throw createError(404, err);
        }
        err.status = 500;
        throw err;
    }
    console.log('stats:');
    console.log(stats);

    //设置的是 response 的 header
    ctx.set('Content-Length', stats.size);
    //设置缓存
    if(!ctx.response.get('Last-Modified')) ctx.set('Last-Modified', stats.mtime.toUTCString());
    if(!ctx.response.get('Cache-Control')){
        const directives = [`max-age=${maxage/1000|0}`];
        if(immutable){
            directives.push('immutable');
        }
        ctx.set('Cache-Control', directives.join(','));
    }

    //type 这样命名真的没问题，会自动转换为 text/xx 这样？
    if(!ctx.type){
        ctx.type = extname(path);
        console.log('extname(path):');
        console.log(extname(path));
        console.log('ctx.type: '+ctx.type);
    } 
    //读取流，为 EventEmitter 的实例
    ctx.body = fs.createReadStream(path);
    return path;
}

function createError(code, err){
    return new Error({
        code,
        err
    });
}

function decode(path){
    try{
        return decodeURIComponent(path);
    }catch(err){
        return -1;
    }
}

module.exports = send;